import * as Koa from 'koa';
import * as dateformat from 'dateformat';

const lengthFormat = (length: number | undefined) => {
  if (length === undefined) return '-';
  else if (length < 1024) return `${length}b`;
  else if (length < 1024 * 1024) return `${(length / 1024).toFixed(2)}kb`;
  else return `${(length / 1024 / 1024).toFixed(2)}mb`;
};

const delayFormat = (delta: number) => {
  return delta < 1000 ? `${delta}ms` : `${(delta / 1000).toFixed(2)}s`;
};

const log = (date: number | Date, arrow: string, method: string, url: string,
  status: number | null = null, length: number | null | undefined = null,
  delay: number | null = null) => {
    const timeFormat = 'HH:MM:ss';
    const dateVal = dateformat(date, timeFormat);
    const statusVal = status === null ? '' : status;
    const lengthVal = length === null ? '' : lengthFormat(length);
    const delayVal = delay === null ? '' : delayFormat(delay);
    const logVal = `[${dateVal}] ${arrow} ${method} ${url} ${statusVal} ${lengthVal} ${delayVal}`;
    console.log(logVal);
};

const logger = (): Koa.Middleware => {
  const func: Koa.Middleware = async (ctx: Koa.Context, next) => {
    const req = ctx.request;
    const start = Date.now();
    log(start, '<--', req.method, req.url);
    await next();
    const res = ctx.res;
    const response = ctx.response;
    // 连接结束时触发
    const onFinish = done.bind(null, 'finish');
    const onClose = done.bind(null, 'close');
    function done (event: string) {
      res.removeListener('finish', onFinish);
      res.removeListener('close', onClose);
      const end = Date.now();
      const status = response.status;
      const delay = end - start;
      const arrow = event === 'finish' ? '-->' : '-x-';
      log(end, arrow, req.method, req.url, status, response.length, delay);
    }
    res.once('finish', onFinish);
    res.once('close', onClose);
  };
  return func;
};

export default logger;

